package container.queue;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.concurrent.PriorityBlockingQueue;

/**
 * https://blog.csdn.net/f641385712/article/details/89538820
 * 基于优先级的阻塞队列（优先级的判断通过构造函数传入的 Compator 对象来决定），但需要注意的是 PriorityBlockingQueue 并不会阻塞数据生产者，而
 * 只会在没有可消费的数据时，阻塞数据的消费者。
 * 因此使用的时候要特别注意，生产者生产数据的速度绝对不能快于消费者消费数据的速度，否则时间一长，会最终耗尽所有的可用堆内存空间。
 * 在实现 PriorityBlockingQueue 时，内部控制线程同步的锁采用的是公平锁。
 * <p>
 * 我们知道队列是遵循先进先出（First-In-First-Out）模式的，但有些时候需要在队列中基于优先级处理对象。
 * 为什么优先级队列，其实很好理解。比如银行的 VIP 客户、各大机场的 VIP 客户的优先登机等，都是优先级队列的体现。而正常排队的都属于普通队列
 * PriorityQueue 类在 Java1.5 中引入的，它是 Java 集合框架的一部分。PriorityQueue 是基于优先堆的一个无界队列，它是一个 Queue
 * 默认情况下它 根据自然排序，当然我们也可以定制比较器，自行自定义排序，从而实现自己的优先级逻辑。
 * <p>
 * 优先队列不允许空值，而且不支持 non-comparable（不可比较）的对象，比如用户自定义的类。
 * 注意：此处需要注意的是，你是基于某个字段做优先级排序，只需要那个字段可比较即可，而不需要整个类都实现比较器接口
 * 优先队列的头是基于自然排序或者 Comparator 排序的最小元素。如果有多个对象拥有同样的排序，那么就可能随机地取其中任意一个。当我们获取队列时，返回队列的头对象。
 * PriorityQueue 是非线程安全的，所以 Java 提供了 PriorityBlockingQueue（实现BlockingQueue接口）用于Java多线程环境。
 * <p>
 * PriorityBlockingQueue 是一个无界有序的阻塞队列，排序规则和 PriorityQueue 一致，只是增加了阻塞操作。同样的该队列不支持插入 null 元素，
 * 同时不支持插入非 comparable 的对象。
 * 该类不保证同等优先级的元素顺序，如果你想要强制顺序，就需要考虑自定义顺序或者是 Comparator 使用第二个比较属性
 * 它的构造函数和 PriorityQueue 基本一样，使用方式也是差不多的。只是它增加了对多线程的处理、以及对阻塞队列特性的支持
 */
public class T06_PriorityBlockingQueue {
    /**
     * （阻塞）队列能解决我们最常规的排队的问题，而优先级队这种数据结构能够解决我们业务中可能会用到的 VIP 排队问题。
     * 比如有个常规的使用场景：优先级消息（MQ消息），有的就是基于 JDK 的优先级队列来实现的
     */
    public static void main(String[] args) {
        // PriorityQueue<String> priorityQueue = new PriorityQueue<>();
        // 指定一个倒序输出的比较器
        PriorityQueue<String> priorityQueue = new PriorityQueue<>(Comparator.reverseOrder());
        priorityQueue.add("orange");
        priorityQueue.add("fig");
        priorityQueue.add("watermelon");
        priorityQueue.add("lemon");
        while (priorityQueue.size() != 0) {
            System.out.println(priorityQueue.remove());
        }

        // 注意的是：它没有提供和 PriorityQueue 一样的只提供比较器的构造函数
        PriorityBlockingQueue<String> priorityBlockingQueue = new PriorityBlockingQueue<>(11, Comparator.reverseOrder());
        priorityBlockingQueue.add("orange");
        priorityBlockingQueue.add("fig");
        priorityBlockingQueue.add("watermelon");
        priorityBlockingQueue.add("lemon");
        while (priorityBlockingQueue.size() != 0) {
            System.out.println(priorityBlockingQueue.remove());
        }
    }
}